package com.mm.util.note;

import cn.hutool.core.codec.Base64Encoder;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 网络链接图片 后缀
 *
 * @author yanglin
 */
public class ImageUtil {

    public final static String TYPE_JPEG = "jpeg";
    public final static String TYPE_PNG = "png";
    public final static String TYPE_GIF = "gif";
    public final static String TYPE_WEBP = "webp";
    public final static String TYPE_BMP = "bmp";
    public final static String TYPE_ICO = "ico";

    /**
     * 读取文件字节识别图片扩展名
     *
     * @param file
     * @return
     * @throws java.io.IOException
     */
    public static String readType(byte[] file) throws IOException {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(file);
        return readType(byteArrayInputStream);
    }

    /**
     * 读取本地文件识别图片扩展名
     *
     * @param file
     * @return
     * @throws java.io.IOException
     */
    public static String readType(File file) throws IOException {

        FileInputStream fis = null;
        try {
            if (!file.exists() || file.isDirectory() || file.length() < 8) {
                throw new IOException("the file [" + file.getAbsolutePath() + "] is not image !");
            }

            fis = new FileInputStream(file);
            return readType(fis);

        } catch (IOException e) {
            throw e;
        } finally {
            try {
                if (fis != null)
                    fis.close();
            } catch (Exception e) {
            }
        }

    }

    /**
     * 输入流识别图片扩展名
     *
     * @param is
     * @return
     * @throws java.io.IOException
     */
    public static String readType(InputStream is) throws IOException {

        byte[] bufHeaders = readInputStreamAt(is, 0, 8);
        if (isJPEGHeader(bufHeaders)) {
            // jpeg需要判定头和尾，但是目前不需要这严谨，为了节约资源注释掉结尾判定
            return TYPE_JPEG;
        }
        if (isPNG(bufHeaders)) {
            return TYPE_PNG;
        }
        if (isGIF(bufHeaders)) {

            return TYPE_GIF;
        }
        if (isWEBP(bufHeaders)) {
            return TYPE_WEBP;
        }
        if (isBMP(bufHeaders)) {
            return TYPE_BMP;
        }
        if (isICON(bufHeaders)) {
            return TYPE_ICO;
        }
        throw new IOException("the image's format is unkown!");
    }


    /**
     * 标示一致性比较
     *
     * @param buf     待检测标示
     * @param markBuf 标识符字节数组
     * @return 返回false标示标示不匹配
     */
    private static boolean compare(byte[] buf, byte[] markBuf) {
        for (int i = 0; i < markBuf.length; i++) {
            byte b = markBuf[i];
            byte a = buf[i];

            if (a != b) {
                return false;
            }
        }
        return true;
    }

    /**
     * @param fis        输入流对象
     * @param skiplength 跳过位置长度
     * @param length     要读取的长度
     * @return 字节数组
     * @throws java.io.IOException
     */
    private static byte[] readInputStreamAt(InputStream fis, long skiplength, int length) throws IOException {
        byte[] buf = new byte[length];
        fis.skip(skiplength);
        fis.read(buf, 0, length);
        return buf;
    }

    /**
     * BMP图片文件的前两个字节
     *
     * @param buf
     * @return
     */
    private static boolean isBMP(byte[] buf) {
        byte[] markBuf = "BM".getBytes();
        return compare(buf, markBuf);
    }

    /**
     * ICON
     *
     * @param buf
     * @return
     */
    private static boolean isICON(byte[] buf) {
        byte[] markBuf = {0, 0, 1, 0, 1, 0, 32, 32};
        return compare(buf, markBuf);
    }

    /**
     * WebP图片识别符
     *
     * @param buf
     * @return
     */
    private static boolean isWEBP(byte[] buf) {
        byte[] markBuf = "RIFF".getBytes();
        return compare(buf, markBuf);
    }

    /**
     * GIF图片识别符
     *
     * @param buf
     * @return
     */
    private static boolean isGIF(byte[] buf) {
        // GIF识别符
        byte[] markBuf = "GIF89a".getBytes();
        if (compare(buf, markBuf)) {
            return true;
        }
        // GIF识别符
        markBuf = "GIF87a".getBytes();
        if (compare(buf, markBuf)) {
            return true;
        }
        return false;
    }

    /**
     * PNG识别符
     *
     * @param buf
     * @return
     */
    private static boolean isPNG(byte[] buf) {
        byte[] markBuf = {(byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
        // new String(buf).indexOf("PNG")>0 //也可以使用这种方式
        return compare(buf, markBuf);
    }

    /**
     * JPEG开始符
     *
     * @param buf
     * @return
     */
    private static boolean isJPEGHeader(byte[] buf) {
        byte[] markBuf = {(byte) 0xff, (byte) 0xd8};
        return compare(buf, markBuf);
    }

    /**
     * JPEG结束符
     *
     * @param buf
     * @return
     */
    private static boolean isJPEGFooter(byte[] buf) {
        byte[] markBuf = {(byte) 0xff, (byte) 0xd9};
        return compare(buf, markBuf);
    }

    /**
     * 本地或网络图片转base64
     * http://www.jsons.cn/img2base64/ 图片Base64编码
     * https://tool.chinaz.com/tools/imgtobase
     * https://tools.pcwanli.com/tools/htmlRun.html HTML在线运行
     * @param imgStr
     * @return
     */
    public static String getImgStrToBase64(String imgStr) {
        InputStream inputStream = null;
        byte[] buffer = null;
        StringBuilder sb = new StringBuilder();
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();){
            //判断网络链接图片文件/本地目录图片文件
            if (imgStr.startsWith("http://") || imgStr.startsWith("https://")) {
                // 创建URL
                URL url = new URL(imgStr);
                // 创建链接
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5000);
                inputStream = conn.getInputStream();
                // 将内容读取内存中
                buffer = new byte[1024];
                int len = -1;
                while ((len = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, len);
                }
                buffer = outputStream.toByteArray();
            } else {
                inputStream = new FileInputStream(imgStr);
                int count = 0;
                while (count == 0) {
                    count = inputStream.available();
                }
                buffer = new byte[count];
                inputStream.read(buffer);
            }
            // https://t.lizi.moe/pc
            String encoderStr = Base64Encoder.encode(buffer);
            // data:image/webp;base64,
            sb.append("data:image/").append(readType(buffer)).append(";base64,").append(replaceEnter(encoderStr));
        } catch (Exception e) {
        } finally {
            if (inputStream != null) {
                try {
                    // 关闭inputStream流
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

    /**
     * 字符替换
     *
     * @param str 字符串
     * @return 替换后的字符串
     */
    public static String replaceEnter(String str) {
        String reg = "[\n-\r]";
        Pattern p = Pattern.compile(reg);
        Matcher m = p.matcher(str);
        return m.replaceAll("");
    }

    public static void main(String[] args) {
        /**
         * https://t.lizi.moe/pc,
         * https://sex.nyan.xyz/api/v2/img,
         * https://www.dmoe.cc/random.php,
         * https://service-dn725wcs-1306777571.gz.apigw.tencentcs.com/release/,
         * https://img.paulzzh.com/touhou/random,
         * https://api.ghser.com/random/api.php
         */
        String url = "https://api.ghser.com/random/api.php";
        String baseStr = getImgStrToBase64(url);
        System.out.println(baseStr);
    }
}
